/* IF2030 - Algorirma dan Struktur Data */
/* Kelas/Kelompok/Tahun  : 03/09/2011 */
/* Tanggal   : 2 Desember 2011 */
/* File      : list.c */
/* Deskripsi : Body dari ADT List Pengguna dan Pertemanannya */

#include "list.h"

void AlokasiPerson(addressPerson *P)
//{ Mengambil memori dari komputer sebagai memori siap pakai untuk elemen }
//{ I.S. Sembarang. }
//{ F.S. P adalah pointer yang sudah dialokasikan alamatnya
//menghasilkan P=Nil apabila memori sudah penuh dan tulis pesan "Alokasi Memori gagal" }
{
    /* KAMUS LOKAL */

    /* ALGORITMA */
    (*P) = (addressPerson) malloc (sizeof(Person));
    if ((*P) == Nil) {
        printf("Alokasi Memori gagal");
    } else {
        NextPerson(*P) = Nil;
    }
}

void AlokasiFriend(addressFriend *P)
//{ Mengambil memori dari komputer sebagai memori siap pakai untuk elemen }
//{ I.S. Sembarang. }
//{ F.S. P adalah pointer yang sudah dialokasikan alamatnya
//menghasilkan P=Nil apabila memori sudah penuh dan tulis pesan "Alokasi Memori gagal" }
{
    /* KAMUS LOKAL */

    /* ALGORITMA */
    (*P) = (addressFriend) malloc (sizeof(Friend));
    if ((*P) == Nil) {
        printf("Alokasi Memori gagal");
    } else {
        NextFriend(*P) = Nil;
    }
}



void DealokasiPerson(addressPerson *P)
// { Mengembalikan memori elemen P ke sistem }
// { I.S. P tidak Nil. }
// { F.S. Memori P dikembalikan ke sistem }
{
    /* KAMUS LOKAL */

    /* ALGORITMA */
    free(*P);
}

void DealokasiFriend(addressFriend *P)
// { Mengembalikan memori elemen P ke sistem }
// { I.S. P tidak Nil. }
// { F.S. Memori P dikembalikan ke sistem }
{
    /* KAMUS LOKAL */

    /* ALGORITMA */
    free(*P);
}

boolean PersonEmpty(ListPerson L)
//{ Mengirim true jika ListPerson kosong }
{
    /* KAMUS LOKAL */

    /* ALGORITMA */
    return (First(L) == Nil) && (Last(L) == Nil);
}

boolean FriendEmpty(ListFriend L)
//{ Mengirim true jika ListFriend kosong }
{
    /* KAMUS LOKAL */

    /* ALGORITMA */
    return (First(L) == Nil) && (Last(L) == Nil);
}

void CreateListPerson(ListPerson *L)
//{ Membentuk ListPerson baru }
//{ I.S. sembarang }
//{ F.S. Terbentuk ListPerson kosong }
{
    /* KAMUS LOKAL */

    /* ALGORITMA */
    First(*L) = Nil;
    Last(*L) = Nil;
}

void CreateListFriend(ListFriend *L)
//{ Membentuk ListFriend baru }
{
    /* KAMUS LOKAL */

    /* ALGORITMA */
    First(*L) = Nil;
    Last(*L) = Nil;
}

addressPerson EmailSearch(ListPerson *LP, string X)
//{ Menghasilkan addressPerson dari user yang memiliki ID email X}
{
    /* KAMUS LOKAL */
    addressPerson P = First(*LP);
    boolean found = false;

    /* ALGORITMA */
    while ((P != Nil) && (!found)) {
        if (strcompare(Email(Data(*P)), X) == 0) {
            found = true;
        } else {
            P = NextPerson(P);
        }
    } ;
    if (found) {
        return P;
    } else {
        return Nil;
    }
}

void SalinData(Person *destination, Person source)
//{ Menyalin seluruh data user dari source ke destination }
//{ I.S. Data destination kosong }
//{ F.S. Data destination = Data source }
{
    /* KAMUS LOKAL */

    /* ALGORITMA */
    strcopy(Email(Data(*destination)), Email(Data(source)));
    strcopy(Nama(Data(*destination)), Nama(Data(source)));
    Data(*destination).Lahir = Data(source).Lahir;
    strcopy(Kota(Data(*destination)), Kota(Data(source)));
    strcopy(Universitas(Data(*destination)), Universitas(Data(source)));
    strcopy(Sma(Data(*destination)), Sma(Data(source)));
}

void InsertPersonSort(ListPerson *LP, Person X)
//{ Menambahkan X sebagai elemen ListPerson L terurut ascending berdasarkan nama }
//{ I.S. L bisa kosong }
//{ F.S. X dialokasikan dan masuk sebagai elemen L terurut ascending berdasar nama }
{
    /* KAMUS LOKAL */
    addressPerson P, P0, P1;

    /* ALGORITMA */
    AlokasiPerson(&P);
    if (P != Nil) {
        SalinData(P, X);
        CreateListFriend(&(Friend(P)));


        if ((First(*LP) == Nil) && (Last(*LP) == Nil)) {
            First(*LP) = P;
            Last(*LP) = First(*LP);
        } else {
            P0 = Nil;
            P1 = First(*LP);

            while ((strcompare(Nama(Data(Info(P))), Nama(Data(Info(P1)))) >= 0) && (NextPerson(P1) != Nil)) {
                P0 = P1;
                P1 = NextPerson(P1);
            }

            if (P0 == Nil) {
                NextPerson(P) = First(*LP);
                First(*LP) = P;
            } else {
                if (NextPerson(P1) == Nil) {
                    if (strcompare(Nama(Data(Info(P))), Nama(Data(Info(P1)))) >= 0) {
                        NextPerson(P1) = P;
                        Last(*LP) = P;
                    } else {
                        NextPerson(P0) = P;
                        NextPerson(P) = P1;
                    }
                } else {
                    NextPerson(P0) = P;
                    NextPerson(P) = P1;
                }
            }
        }
    }
}
void InsertFriend(ListFriend *L, addressPerson X)
//{ Menambahkan X sebagai elemen terakhir ListPerson L }
//{ I.S. L bisa kosong }
//{ F.S. X dialokasikan dan masuk sebagai elemen terakhir L }
{
    /* KAMUS LOKAL */
    addressFriend F;

    /* ALGORITMA */
    AlokasiFriend(&F);
    if (F != Nil) {
        (*F).Person = X;
        NextFriend(F) = Nil;

        if ((First(*L) == Nil) && (Last(*L) == Nil)) {
            First(*L) = F;
            Last(*L) = First(*L);
        } else {
            NextFriend(Last(*L)) = F;
            Last(*L) = F;
        }
    }
}

void PrintTableHeader ()
//{ Mencetak header tampilan tabel ListPerson sebagai baris informasi isi tabel }
//{ I.S. Sembarang }
//{ F.S. Baris pertama tampilan tabel yang berisi informasi isi tabel tercetak }
{
    printf("\n+---------------------------+---------------------------+------------+----------------------+-----------------+----------------------+");
    printf("\n| EMAIL                     | NAMA LENGKAP              | TTL        | KOTA ASAL            | UNIVERSITAS     | SEKOLAH              |");
    printf("\n+---------------------------+---------------------------+------------+----------------------+-----------------+----------------------+");
}

void PrintTableFooter ()
//{ Mencetak footer tampilan tabel ListPerson sebagai penutup tabel }
//{ I.S. Sembarang }
//{ F.S. Baris terakhir tampilan tabel sebagai penutup tabel tercetak }
{
    printf("\n+---------------------------+---------------------------+------------+----------------------+-----------------+----------------------+");
}


void PrintPerson(addressPerson P)
//{ Mencetak isi data user dari user yang beralamatkan P }
//{ I.S. Sembarang }
//{ F.S. Data user beralamatkan P tercetak }
{
    /* KAMUS LOKAL */
    string tmp;

    /* ALGORITMA */
    printf("\n| %-25.25s", Email(Data(Info(P))));
    printf(" | %-25.25s", Nama(Data(Info(P))));
    DateToStr(Lahir(Data(Info(P))), tmp);
    printf(" | %10.10s", tmp);
    if (isBlank(Kota(Data(*P)))) {
        printf(" | %-20.20s", "NIL");
    } else {
        printf(" | %-20.20s",Kota(Data(Info(P))));
    }

    if (isBlank(Universitas(Data(*P)))) {
        printf(" | %-15.15s", "NIL");
    } else {
        printf(" | %-15.15s", Universitas(Data(Info(P))));
    }

    if (isBlank(Sma(Data(Info(P))))) {
        printf(" | %-20.20s", "NIL");
    } else {
        printf(" | %-20.20s |",Sma(Data(Info(P))));
    }
}

void PrintPersonMasking(addressPerson P, boolean FirstFriend)
//{ Mencetak isi data user dari user yang beralamatkan P dan menyamarkan tanggal lahir bila belum berteman dengannya }
//{ I.S. Sembarang }
//{ F.S. Data user beralamatkan P tercetak, jika user beralamatkan P belum
//berteman, maka field tanggal lahir dicetak XX-XX-XXXX }
{
    /* KAMUS LOKAL */

    /* ALGORITMA */
    /* User dan Friend harus bersifat reciprocal untuk melihat data lengkap */
    if (FirstFriend) {
        PrintPerson(P);
    } else { /* Jika friend belum berteman dengan user, maka akan ada masking data */
        printf("\n| %-25.25s", Email(Data(Info(P))));
        printf(" | %-25.25s", Nama(Data(Info(P))));
        printf(" | %10.10s", "XX-XX-XXXX");
        if (isBlank(Kota(Data(*P)))) {
            printf(" | %-20.20s", "NIL");
        } else {
            printf(" | %-20.20s",Kota(Data(Info(P))));
        }

        if (isBlank(Universitas(Data(*P)))) {
            printf(" | %-15.15s", "NIL");
        } else {
            printf(" | %-15.15s", Universitas(Data(Info(P))));
        }

        if (isBlank(Sma(Data(Info(P))))) {
            printf(" | %-20.20s", "NIL");
        } else {
            printf(" | %-20.20s |",Sma(Data(Info(P))));
        }
    }
}

void PrintSamePerson(ListPerson LP, addressPerson CUser, string Pilihan)
//{ Mencetak data user yang merupakan 1st, 2nd, dan 3rd friend dari CUser dan memiliki data SMA, universitas,
//atau kota asal yang sama tergantung masukan}
//{ I.S. LP tidak kosong }
//{ F.S. Jika Pilihan = school maka ditampilkan data user yang merupakan 1st, 2nd, atau 3rd friend dengann CUser
//yang memiliki SMA atau universitas yang sama dengan CUser, jika Pilihan = hometown, maka ditampilkan
//yang memiliki kota asal yang sama dengan CUser }
{
    /* KAMUS LOKAL */
    addressPerson CP = First(LP);
    addressPerson* TabSamePerson;
    int i = 0;
    int j = 1;
    int k;

    /* ALGORITMA */
    TabSamePerson = (addressPerson *) malloc ((NbPerson(LP)*sizeof(addressPerson)));
    while (CP != Nil) {
        if (CP != CUser) {
            //printf("[%s] >> [%s] : %d friend\n",Email(Data(*CUser)),Email(Data(*CP)),WhichFriend(CUser,CP));
            if (WhichFriend(CUser,CP)) {
                if (!strcompare(Pilihan,"school")) {
                    if ((!strcompare(Sma(Data(*CUser)),Sma(Data(*CP)))) || (!strcompare(Universitas(Data(*CUser)),Universitas(Data(*CP))))) {
                        TabSamePerson[i] = CP;
                        //printf("\n>>[%p]\n",TabSamePerson[i]);
                        i++;
                    }
                } else if (!strcompare(Pilihan,"hometown")) {
                    if (!strcompare(Kota(Data(*CUser)),Kota(Data(*CP)))) {
                        TabSamePerson[i] = CP;
                        //printf("\n>>[%p]\n",TabSamePerson[i]);
                        i++;
                    }
                }
            }
        }
        CP = NextPerson(CP);
    }
    PrintTableHeader();
    while (j <= 3) {
        k = 0;
        printf("\nTeman Level: %d",j);
        while (k < i) {
            if (WhichFriend(CUser,TabSamePerson[k]) == j) {
                PrintPersonMasking(TabSamePerson[k],IsFirstFriend(TabSamePerson[k],CUser));
            }
            k++;
        }
        j++;
    }
    PrintTableFooter();
}


void DelFirstFriend(ListFriend *LF, addressFriend *P)
//{ Menghapus elemen pertama dari ListFriend LF dan mengeluarkan alamat yang dihapus}
//{ I.S. LF tidak kosong }
//{ F.S. Elemen pertama list dihapus, nilai address disimpan di P, P belum didealokasi }
{
    /* KAMUS LOKAL */

    /* ALGORITMA */
    (*P) = First(*LF);
    First(*LF) = NextFriend(First(*LF));
    if (*P == Last(*LF)) {
        Last(*LF) = Nil;
    }
    NextFriend(*P) = Nil;
}

void DelFriend(ListFriend *LF, addressFriend *P)
//{ Menghapus elemen beralamat P dari ListFriend LF dan mengeluarkan alamat yang dihapus }
//{ I.S. LF tidak kosong }
//{ F.S. Elemen beralamat P dari list dihapus, nilai address disimpan di P,
//P didealokasi}
{
    /* KAMUS LOKAL */
    addressFriend Prec = First(*LF);

    /* ALGORITMA */
    if (*P != Nil) {
        if (First(*LF) == *P) {
            DelFirstFriend(LF,P);
        } else if (Last(*LF) == *P) {
            DelLastFriend(LF,P);
        } else {
            while (NextFriend(Prec) != *P) {
                Prec = NextFriend(Prec);
            }
            NextFriend(Prec) = NextFriend(*P);
        }
        DealokasiFriend(P);
    }
}

void DelLastFriend(ListFriend *LF, addressFriend *P)
//{ Menghapus elemen terakhir dari ListFriend LF dan mengeluarkan alamat yang dihapus}
//{ I.S. LF tidak kosong }
//{ F.S. Elemen terakhir list dihapus, nilai address disimpan di P, P belum didealokasi }
{
    /* KAMUS LOKAL */
    addressFriend PrecLast;

    /* ALGORITMA */
    (*P) = Last(*LF);
    PrecLast = First(*LF);
    if (First(*LF) == Last(*LF)) {
        DelFirstFriend(LF,P);
    } else {
        while (NextFriend(PrecLast) != Last(*LF)) {
            PrecLast = NextFriend(PrecLast);
        }
        NextFriend(PrecLast) = Nil;
        Last(*LF) = PrecLast;
    }
}

void DelAllFriend(ListFriend *LF)
//{ Menghapus semua elemen dari ListFriend LF dan mendealokasikan semua memori elemen }
//{ I.S. LF tidak kosong }
//{ F.S. Semua Elemen dari list dihapus, semua memori didealokasi }
{
    addressFriend p;
    if (!FriendEmpty(*LF)) {
        while (!FriendEmpty(*LF)) {
            DelFirstFriend(LF,&p);
            DealokasiFriend(&p);
        } ;
    }
}

void DelFirstPerson(ListPerson *LP, addressPerson *P)
//procedure DelFirstPerson(input/output LP : ListFriend, output P : addressFriend)
//{ Menghapus elemen pertama dari ListPerson LP dan mengeluarkan alamat yang dihapus}
//{ I.S. LP tidak kosong }
//{ F.S. Elemen pertama list dihapus, nilai address disimpan di P, P belum didealokasi }
{
    /* KAMUS LOKAL */
    addressFriend userfr;
    addressPerson userpp;

    /* ALGORITMA */
    (*P) = First(*LP);
    First(*LP) = NextPerson(First(*LP));
    if (First(*LP) == Last(*LP)) {
        Last(*LP) = Nil;
    }
    NextPerson(*P) = Nil;
    DelAllFriend(&((**P).Friend));
    userpp = First(*LP);
    while(userpp != Nil) {
        userfr = First(Friend(userpp));
        while(userfr != Nil) {
            if ((*userfr).Person == *P) {
                DelFriend(&Friend(userpp),&userfr);
                break;
            }
            userfr = NextFriend(userfr);
        }
        userpp = NextPerson(userpp);
    }
}

void DelLastPerson(ListPerson *LP, addressPerson *P)
//procedure DelLastPerson(input/output LP : ListFriend, output P : addressFriend)
//{ Menghapus elemen terakhir dari ListPerson LP dan mengeluarkan alamat yang dihapus}
//{ I.S. LP tidak kosong }
//{ F.S. Elemen terakhir list dihapus, nilai address disimpan di P, P belum didealokasi }
{
    /* KAMUS LOKAL */
    addressPerson PrecLast, userpp;
    addressFriend userfr;

    /* ALGORITMA */
    (*P) = Last(*LP);
    PrecLast = First(*LP);
    if (First(*LP) == Last(*LP)) {
        DelFirstPerson(LP,P);
    } else {
        while (NextPerson(PrecLast) != (*P)) {
            PrecLast = NextPerson(PrecLast);
        }
        NextPerson(PrecLast) = Nil;
        Last(*LP) = PrecLast;
        NextPerson(*P) = Nil;
        DelAllFriend(&((**P).Friend));
    }
    userpp = First(*LP);
    while(userpp != Nil) {
        userfr = First(Friend(userpp));
        while(userfr != Nil) {
            if ((*userfr).Person == *P) {
                DelFriend(&Friend(userpp),&userfr);
                break;
            }
            userfr = NextFriend(userfr);
        }
        userpp = NextPerson(userpp);
    }
}

void DelPerson(ListPerson *LP, addressPerson *P)
//procedure DelPerson(input/output LP : ListFriend, input/output P : addressFriend)
//{ Menghapus elemen beralamat P dari ListPerson LP dan mengeluarkan alamat yang dihapus}
//{ I.S. LP tidak kosong }
//{ F.S. Elemen beralamat P list dihapus, nilai address disimpan di P, P belum didealokasi }
{
    /* KAMUS LOKAL */
    addressPerson Prec, userpp;
    addressFriend userfr;

    /* ALGORITMA */
    if (First(*LP) == *P) {
        DelFirstPerson(LP,P);
    } else if (Last(*LP) == *P) {
        DelLastPerson(LP,P);
    } else {
        Prec = First(*LP);
        while (NextPerson(Prec) != *P) {
            Prec = NextPerson(Prec);
        }
        NextPerson(Prec) = NextPerson(*P);
        NextPerson(*P) = Nil;
        DelAllFriend(&((**P).Friend));
        userpp = First(*LP);
        while(userpp != Nil) {
            userfr = First(Friend(userpp));
            while(userfr != Nil) {
                if ((*userfr).Person == *P) {
                    DelFriend(&Friend(userpp),&userfr);
                    break;
                }
                userfr = NextFriend(userfr);
            }
            userpp = NextPerson(userpp);
        }
    }
}

void DelAllPerson(ListPerson *LP)
//{ Menghapus semua elemen dari ListPerson LP dan mendealokasikan memori yang dipakai}
//{ I.S. LP tidak kosong }
//{ F.S. Semua elemen di list dihapus, semua memori yang dipakai didealokasi }
{
    /* KAMUS LOKAL */
    addressPerson p;

    /* ALGORITMA */
    if (!PersonEmpty(*LP)) {
        while (!PersonEmpty(*LP)) {
            DelFirstPerson(LP,&p);
            DealokasiPerson(&p);
        }
    }
}


int NbPerson(ListPerson LP)
//{ Menghasilkan jumlah elemen pada ListPerson LP }
{
    /* KAMUS LOKAL */
    int N = 0;
    addressPerson CP = First(LP);

    /* ALGORITMA */
    while (CP != Nil) {
        N++;
        CP = NextPerson(CP);
    }
    return N;
}

void ResortListPerson(ListPerson *LP, addressPerson P)
/* Menyusun kembali list LP akibat perubahan data pada Person dengan address P */
/* I.S. P telah terdefinisi dan ada pada LP. LP tidak kosong.
        LP sudah terurut berdasarkan data nama, tetapi salah hanya pada bagian P */
/* F.S. LP terurut berdasarkan nama */
{
    /* KAMUS LOKAL */
    addressPerson P0, P1;

    /* ALGORITMA */
    P0 = Nil;
    P1 = First(*LP);
    while (P1 != P) {
        P0 = P1;
        P1 = NextPerson(P1);
    }

    if (P0 != Nil) {
        NextPerson(P0) = NextPerson(P1);
        NextPerson(P1) = Nil;
    } else {
        First(*LP) = NextPerson(P1);
        if (First(*LP) == Nil) {
            Last(*LP) = Nil;
        }
        NextPerson(P1) = Nil;
    }

    if ((First(*LP) == Nil) && (Last(*LP) == Nil)) {
        First(*LP) = P;
        Last(*LP) = First(*LP);
    } else {
        P0 = Nil;
        P1 = First(*LP);

        while ((strcompare(Nama(Data(Info(P))), Nama(Data(Info(P1)))) >= 0) && (NextPerson(P1) != Nil)) {
            P0 = P1;
            P1 = NextPerson(P1);
        }

        if (P0 == Nil) {
            NextPerson(P) = First(*LP);
            First(*LP) = P;
        } else {
            if (NextPerson(P1) == Nil) {
                if (strcompare(Nama(Data(Info(P))), Nama(Data(Info(P1)))) >= 0) {
                    NextPerson(P1) = P;
                    Last(*LP) = P;
                } else {
                    NextPerson(P0) = P;
                    NextPerson(P) = P1;
                }
            } else {
                NextPerson(P0) = P;
                NextPerson(P) = P1;
            }
        }
    }
}

void PrintPersonSort(ListPerson *LP, string Pilihan, boolean AscSortMode)
//{ Melakukan print terhadap ListPerson dengan mengurutkannya sesuai input terlebih dahulu }
//{ I.S. LP terdefinisi dan tidak kosong }
//{ F.S. LP dicetak terurut berdasar input Pilihan dan SortMode, jika SortMode = asc maka akan diurut meningkat sedangkan jika
//SortMode = desc maka akan diurut menurun }
{
    /* KAMUS LOKAL */
    addressPerson* TabSortPerson;
    addressPerson CP = First(*LP);
    int i = 0;
    int k = 0;

    /* ALGORITMA */
    i = 0;

    /* Alokasi Array TabSortPerson dan mengisi nilainya */
    TabSortPerson = (addressPerson *) malloc ((NbPerson(*LP)*sizeof(addressPerson)));

    while (CP != Nil) {
        TabSortPerson[i] = CP;
        CP = NextPerson(CP);
        i++;
    }

    /* Sorting data dengan urutan menaik menggunakan metode Quick Sort */
    QuickSortTablePerson(TabSortPerson, 0, NbPerson(*LP)-1, Pilihan);

    if (AscSortMode) {
        k = 0;
        while (k<i) {
            PrintPerson(TabSortPerson[k]);
            k++;
        }
    } else {
        k = i-1;
        while (k>=0) {

            PrintPerson(TabSortPerson[k]);
            k--;
        }
    }
}


boolean IsFirstFriend(addressPerson user, addressPerson userfriend)
//{ Menghasilkan true bila user berteman dengan userfriend }
{
    /* KAMUS LOKAL */
    addressFriend F = First(Friend(user));
    boolean Found = false;

    /* ALGORITMA */
    while ((F != Nil) && (Found != true)) {
        if ((*F).Person == userfriend) {
            Found = true;
        } else {
            F = NextFriend(F);
        }
    }
    return Found;
}

boolean IsSecondFriend(addressPerson user, addressPerson userfriend)
//{ Menghasilkan true bila userfriend merupakan second friend dari user }
{
    /* KAMUS LOKAL */
    addressFriend CF = First(Friend(user));
    boolean found = false;

    /* ALGORITMA */
    while (CF != Nil) {
        if (IsFirstFriend((*CF).Person,userfriend)) {
            found = true;
            break;
        } else {
            CF = NextFriend(CF);
        }
    }
    return found;
}

boolean IsThirdFriend(addressPerson user, addressPerson userfriend)
//{ Menghasilkan true bila userfriend merupakan third friend dari user }
{
    /* KAMUS LOKAL */
    addressFriend CF = First(Friend(user));
    boolean found = false;

    /* ALGORITMA */
    while (CF != Nil) {
        if (IsSecondFriend((*CF).Person,userfriend)) {
            found = true;
            break;
        } else {
            CF = NextFriend(CF);
        }
    }
    return found;
}

int WhichFriend(addressPerson user, addressPerson userfriend)
//{ Menghasilkan derajat pertemanan paling rendah dari userfriend terhadap user }
{
    /* KAMUS LOKAL */

    /* ALGORITMA */
    if (IsFirstFriend(user,userfriend)) {
        return 1;
    } else if (!IsFirstFriend(user,userfriend) && IsSecondFriend(user,userfriend)) {
        return 2;
    } else if ((!IsFirstFriend(user,userfriend) && !IsSecondFriend(user,userfriend)) && IsThirdFriend(user,userfriend)) {
        return 3;
    } else {
        return 0;
    }
}
void QuickSortTablePerson(addressPerson *TabP, int first, int last, string pilihan)
//{ Melakukan proses sorting terhadap array TabP yang berisi addressPerson sesuai pilihan dari masukan }
//{ I.S. TabP terdefinisi dan berisi addressPerson, first bernilai awal elemen TabP ygb akan diuet dan last adalah elemen terakhirnya }
//{ F.S. TabP terurut menaik berdasar input Pilihan }
{
    /* KAMUS LOKAL */
    int pivot, i, j;
    addressPerson temp;

    /* ALGORITMA */
    if (first < last) {
        pivot = first;
        i = first;
        j = last;

        while(i < j) {
            if (strcompare(pilihan,"email") == 0) {
                while ((strcompare(Email(Data(Info(TabP[i]))), Email(Data(Info(TabP[pivot])))) <= 0) && (i < last))
                    i++;
                while (strcompare(Email(Data(Info(TabP[j]))), Email(Data(Info(TabP[pivot])))) == 1)
                    j--;
            } else if (strcompare(pilihan,"name") == 0) {
                while ((strcompare(Nama(Data(Info(TabP[i]))), Nama(Data(Info(TabP[pivot])))) <= 0) && (i < last))
                    i++;
                while (strcompare(Nama(Data(Info(TabP[j]))), Nama(Data(Info(TabP[pivot])))) == 1)
                    j--;
            } else if (strcompare(pilihan,"birthday") == 0) {
                while ((IsLess(Lahir(Data(Info(TabP[i]))), Lahir(Data(Info(TabP[pivot])))) || (IsSame(Lahir(Data(Info(TabP[i]))), Lahir(Data(Info(TabP[pivot])))))) && (i < last))
                    i++;
                while (IsLess(Lahir(Data(Info(TabP[pivot]))), Lahir(Data(Info(TabP[j])))))
                    j--;
            } else if (strcompare(pilihan,"hometown") == 0) {
                while ((strcompare(Kota(Data(Info(TabP[i]))), Kota(Data(Info(TabP[pivot])))) <= 0) && (i < last))
                    i++;
                while (strcompare(Kota(Data(Info(TabP[j]))), Kota(Data(Info(TabP[pivot])))) == 1)
                    j--;
            } else if (strcompare(pilihan,"university") == 0) {
                while ((strcompare(Universitas(Data(Info(TabP[i]))), Universitas(Data(Info(TabP[pivot])))) <= 0) && (i < last))
                    i++;
                while (strcompare(Universitas(Data(Info(TabP[j]))), Universitas(Data(Info(TabP[pivot])))) == 1)
                    j--;
            } else if (strcompare(pilihan,"highschool") == 0) {
                while ((strcompare(Sma(Data(Info(TabP[i]))), Sma(Data(Info(TabP[pivot])))) <= 0) && (i < last))
                    i++;
                while (strcompare(Sma(Data(Info(TabP[j]))), Sma(Data(Info(TabP[pivot])))) == 1)
                    j--;
            }

            if (i < j) {
                temp = TabP[i];
                TabP[i] = TabP[j];
                TabP[j] = temp;
            }
        }

        temp = TabP[pivot];
        TabP[pivot] = TabP[j];
        TabP[j] = temp;
        QuickSortTablePerson(TabP, first, j-1, pilihan);
        QuickSortTablePerson(TabP, j+1, last, pilihan);
    }
}

void PrintBirthday (ListPerson *LP, string email, date today, int Hari)
/* Mencetak first friend yang berulang tahun dalam rentang today dalam beberapa Hari hari kedepan */
/* I.S: LP, email, hari terdefinisi. today adalah date yang valid */
{
    /* KAMUS LOKAL */
    addressPerson P;
    addressFriend F;
    date tmpDate;
    int n;

    /* ALGORITMA */
    tmpDate = today;
    PrintTableFooter();
    printf("------+");
    printf("\n| EMAIL                     | NAMA LENGKAP              | TTL        | KOTA ASAL            | UNIVERSITAS     | SEKOLAH              | YEAR |");
    PrintTableFooter();
    printf("------+");

    for (n=0; n<=Hari; n++) {
        P = EmailSearch(LP, email);
        F = First(Friend(P));
        while (F!=Nil) {
            if (IsSameDM(Lahir(Data(Info((*F).Person))), tmpDate)) {
                /* User dan Friend harus bersifat reciprocal untuk melihat data lengkap */
                PrintPersonMasking((*F).Person, IsFirstFriend((*F).Person, P));
                printf(" %.4d |", tmpDate.YY);
            }
            F = NextFriend(F);
        }
        tmpDate = NextDay(tmpDate);
    }
    PrintTableFooter();
    printf("------+\n");
}
